package com.qitmiaojie.service.impl;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qitmiaojie.controller.utils.Result;
import com.qitmiaojie.mapper.UserMapper;
import com.qitmiaojie.pojo.Health;
import com.qitmiaojie.pojo.User;
import com.qitmiaojie.pojo.dto.HealthCount;
import com.qitmiaojie.pojo.dto.HealthDto;
import com.qitmiaojie.service.HealthService;
import com.qitmiaojie.mapper.HealthMapper;
import com.qitmiaojie.utils.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@Slf4j
public class HealthServiceImpl extends ServiceImpl<HealthMapper, Health>
    implements HealthService{

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private HealthMapper healthMapper;
    @Autowired
    private UserMapper userMapper;
    @Override
    public Result addHealth(Health health) {

        if (health.getId() == null){
            User CONTEXT_USER = userMapper.selectByUsername(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
            health.setUid(CONTEXT_USER.getId());
            health.setDate(LocalDateTime.now());
            save(health);
            return Result.success("上报成功",CONTEXT_USER.getId());
        }

        updateById(health);
        return Result.success("修改成功！",null);


    }

    @Override
    public Result findPageById() {
        User CONTEXT_USER = userMapper.selectByUsername(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        IPage<Health> page = new Page(1,5);
        page(page,new LambdaQueryWrapper<Health>()
                .eq(Health::getUid, CONTEXT_USER.getId()).orderByDesc(Health::getDate));
        List<HealthDto> healthDtos = this.HandlerHealthDtos(page);
        return Result.success(healthDtos);
    }

    private List<HealthDto> HandlerHealthDtos(IPage<Health> page) {
        return page.getRecords().stream().map(new Function<Health, HealthDto>() {
                @Override
                public HealthDto apply(Health health) {
                    HealthDto healthDto = BeanCopyUtils.copyBean(health, HealthDto.class);
                    healthDto.setKangyuan(health.getKangyuan());

                    healthDto.setZhengzhuang(("是" .equals(health.getJialiu()) ?
                            "/甲流" : "疑似" .equals(health.getJialiu()) ? "/疑似甲流" : "")
                            + ("是" .equals( health.getXinguan()) ? "/新冠" : "疑似" .equals( health.getXinguan()) ? "/疑似新冠" : "")
                            + ("是".equals(health.getNuoru())? "/诺如" : "疑似" .equals(health.getNuoru()) ? "/疑似诺如" : ""));
                    return healthDto;
                }
            }).collect(Collectors.toList());
    }

    @Override
    public Result getSourceData() {

        //查询近一周确诊人数
        //1.查询现在时间
        LocalDateTime now = LocalDateTime.now();
        String localDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        //2 往前推6天
        Period period = Period.ofDays(6);
        LocalDateTime sixDaysAgo = now.minus(period);
        String sixDate = sixDaysAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        //2.2 between and  +1
        List<HealthCount> healthCounts = healthMapper.selectSymptomCounts(sixDate,localDate+1);
        List<Map<String, Object>> data = new ArrayList<>();
/*"result": [
    {"name": "甲流", "confirmed": 43, "suspected": 85},
    {"name": "诺如", "confirmed": 83, "suspected": 73},
    {"name": "新冠", "confirmed": 86, "suspected": 65},
    {"name": "其他", "confirmed": 72, "suspected": 53}
  ]*/
        HashMap<String, Object> jialiuMap = new HashMap<>();
        jialiuMap.put("name","甲流");
        HashMap<String, Object> xinguanMap = new HashMap<>();
        xinguanMap.put("name","新冠");
        HashMap<String, Object> nuoruMap = new HashMap<>();
        nuoruMap.put("name","诺如");
        for (HealthCount healthCount : healthCounts) {
            if ("jialiu".equals(healthCount.getType())){
                if ("是".equals(healthCount.getSymptom())){
                    jialiuMap.put("confirmed",healthCount.getCount());
                }else {
                    jialiuMap.put("suspected",healthCount.getCount());
                }
            }

            if ("xinguan".equals(healthCount.getType())){
                if ("是".equals(healthCount.getSymptom())){
                    xinguanMap.put("confirmed",healthCount.getCount());
                }else {
                    xinguanMap.put("suspected",healthCount.getCount());
                }
            }
            if ("nuoru".equals(healthCount.getType())){
                if ("是".equals(healthCount.getSymptom())){
                    nuoruMap.put("confirmed",healthCount.getCount());
                }else {
                    nuoruMap.put("suspected",healthCount.getCount());
                }
            }
        }
        data.add(jialiuMap);
        data.add(xinguanMap);
        data.add(nuoruMap);
        return Result.success(data);
    }

    @Override
    public Result getSourceDataTotal() {


        if (redisTemplate.opsForValue().get("sourceDataTotal") != null){
            // 尝试从缓存中读取数据
            String data = redisTemplate.opsForValue().get("sourceDataTotal");
            if (data != null) {
                log.info("走了缓存...");
                return Result.success(JSON.parseObject(data, new TypeReference<List<Map<String, Object>>>() {}));
            }
        }


        /*[
                  {
                      name: '诺如',
                      type: 'line',
                      stack: 'Total',
                      areaStyle: {},
                      emphasis: {
                          focus: 'series'
                      },
                      data: [150, 232, 201, 154, 190, 330, 410]
                  },
              ]*/
        /**/
        //首先定义甲流的总确诊人数
        Map<String, Object> series1 = new HashMap<>();
        series1.put("name", "甲流");
        series1.put("type", "line");
        series1.put("stack", "Total");
        series1.put("areaStyle", new HashMap<>());
        series1.put("emphasis", new HashMap<String,Object>() {{
            put("focus", "series");
        }});

        List<Map<String, Object>> jialiu = healthMapper.selectConfirmedCount("jialiu");
        List<Integer> jialiuList = new ArrayList<>(Arrays.asList(new Integer[12]));
        Collections.fill(jialiuList, 0);

        for (int i = 0; i < jialiu.size(); i++) {
            Map<String, Object> map = jialiu.get(i);
            log.info("map = " + map.toString());

            Object month = map.get("MONTH");
            int key = Integer.parseInt(month.toString());
            Integer value = Integer.parseInt(map.get("COUNT").toString());
            jialiuList.set(key-1,value);
        }


        series1.put("data",jialiuList);

        // 定义第二个图表系列
        Map<String, Object> series2 = new HashMap<>();
        series2.put("name", "新冠");
        series2.put("type", "line");
        series2.put("stack", "Total");
        series2.put("areaStyle", new HashMap<>());
        series2.put("emphasis", new HashMap<String,Object>() {{
            put("focus", "series");
        }});

        List<Integer> xinguanList = new ArrayList<>(Arrays.asList(new Integer[12]));
        Collections.fill(xinguanList, 0);
        List<Map<String, Object>> xinguan = healthMapper.selectConfirmedCount("xinguan");
        for (int i = 0; i < xinguan.size(); i++) {
            Map<String, Object> map = xinguan.get(i);
            Object month = map.get("MONTH");
            int key = Integer.parseInt(month.toString());
            Integer value = Integer.parseInt(map.get("COUNT").toString());
            xinguanList.set(key-1,value);
        }


        series2.put("data",xinguanList);
        // 定义第三个图表系列
        Map<String, Object> series3 = new HashMap<>();
        series3.put("name", "诺如");
        series3.put("type", "line");
        series3.put("stack", "Total");
        series3.put("areaStyle", new HashMap<>());
        series3.put("emphasis", new HashMap<String,Object>() {{
            put("focus", "series");
        }});
        List<Integer> nuoruList = new ArrayList<>(Arrays.asList(new Integer[12]));
        Collections.fill(nuoruList, 0);

        List<Map<String, Object>> nuoru = healthMapper.selectConfirmedCount("nuoru");
        for (int i = 0; i < nuoru.size(); i++) {
            Map<String, Object> map = nuoru.get(i);
            Object month = map.get("MONTH");
            int key = Integer.parseInt(month.toString());
            Integer value = Integer.parseInt(map.get("COUNT").toString());
            nuoruList.set(key-1,value);
        }
        series3.put("data",nuoruList);


        List<Map<String, Object>> data = new ArrayList<>();
        data.add(series1);
        data.add(series2);
        data.add(series3);
        //存入缓存 三十分钟后自动删除
        redisTemplate.opsForValue().set("sourceDataTotal", JSON.toJSONString(data),30, TimeUnit.MINUTES);

        return Result.success(data);
    }

    @Override
    public Result listByPage(Integer currentPage) {
        IPage<Health> iPage = new Page<>(currentPage,10);
        page(iPage,new LambdaQueryWrapper<Health>().orderByDesc(Health::getDate));
        List<HealthDto> healthDtos = this.HandlerHealthDtos(iPage);
        return Result.success(healthDtos);
    }

    @Override
    public Result editRecovery(String id) {
        LambdaUpdateWrapper<Health> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Health::getRecovery,1);
        updateWrapper.eq(Health::getId,id);
        update(updateWrapper);
        return Result.success("状态修改成功！",null);
    }
}




